home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Libraries / stdwin / Packs / vt / vtansi.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-02-19  |  11.4 KB  |  539 lines  |  [TEXT/????]

  1. /* ANSI escape sequence interpreter */
  2.  
  3. /* There is some ugly code here, since I assume that code looking
  4.    at the input a character at a time is very time-critical.
  5.    Action functions are called with the start of the text to process,
  6.    and return a pointer to where they left off.
  7.    When an action function hits the end of the string,
  8.    it returns NULL and sets the action pointer to the function to
  9.    call next (often itself), or to NULL for the default.
  10.    A non-NULL return implies that the default action function must
  11.    be called next and the action pointer is irrelevant.
  12.    Remember that the general form of most ANSI escape sequences is
  13.     ESC [ <n1> ; <n2> ; ... <c>
  14.    where <c> is the command code and <n1>, <n2> etc. are optional
  15.    numerical parameters.
  16. */
  17.  
  18. #include "vtimpl.h"
  19.  
  20. #ifdef DEBUG
  21.  /* Let it be heard that a command was not recognized */
  22. #define FAIL() wfleep()
  23. #else
  24. /* Silently ignore unrecognized commands */
  25. #define FAIL() 0
  26. #endif
  27.  
  28. /* Function prototypes */
  29.  
  30. STATIC char *def_action _ARGS((VT *vt, char *text, char *end));
  31. STATIC char *esc_action _ARGS((VT *vt, char *text, char *end));
  32. STATIC char *ansi_params _ARGS((VT *vt, char *text, char *end));
  33. STATIC char *ansi_execute _ARGS((VT *vt, char *text));
  34. STATIC void vtsetoptions _ARGS((VT *vt, bool flag));
  35. STATIC void vtsetattrlist _ARGS((VT *vt));
  36.  
  37. /* Output a string, interpreting ANSI escapes */
  38.  
  39. void
  40. vtansiputs(vt, text, len)
  41.     VT *vt;
  42.     char *text;
  43.     int len;
  44. {
  45.     char *end;
  46.  
  47. #ifndef NDEBUG
  48.     if (vt->scr_top < 0 || vt->scr_top > vt->rows) {
  49.         fprintf(stderr, "vtansiputs: scr_top = %d\n", vt->scr_top);
  50.         vtpanic("vtansiputs: bad scr_top");
  51.     }
  52. #endif
  53.  
  54.     if (len < 0)
  55.         len = strlen(text);
  56.     end = text + len;
  57.  
  58.     D( printf("vtansiputs %d chars\n", len) );
  59.     
  60.     /* Pick up where the last call left us behind  */
  61.     if (vt->action != NULL)
  62.         text = (*vt->action)(vt, text, end);
  63.  
  64.     /* Start in default state until text exhausted */
  65.     while (text != NULL)
  66.         text = def_action(vt, text, end);
  67.  
  68.     /* Execute delayed scrolling */
  69.     vtsync(vt);
  70.     D( printf("vtansiputs returns\n") );
  71. }
  72.  
  73. /* Default action function */
  74.  
  75. STATIC char *
  76. def_action(vt, text, end)
  77.     VT *vt;
  78.     char *text, *end;
  79. {
  80. again:
  81.     for (;;) {
  82.         if (text >= end) {
  83.             vt->action = NULL;
  84.             return NULL;
  85.         }
  86.         if (PRINTABLE(*text))
  87.             break;
  88.         switch (*text++) {
  89.  
  90.         case ESC:    /* ESC */
  91.             return esc_action(vt, text, end);
  92.         
  93.         case BEL:    /* Bell */
  94.             if (vt->visualbell) {
  95.                 VTBEGINDRAWING(vt);
  96.                 vtinvert(vt, 0, 0, vt->rows, vt->cols);
  97.                 VTENDDRAWING(vt);
  98.                 VTBEGINDRAWING(vt);
  99.                 vtinvert(vt, 0, 0, vt->rows, vt->cols);
  100.                 VTENDDRAWING(vt);
  101.             }
  102.             else {
  103.                 wfleep();
  104.             }
  105.             break;
  106.         
  107.         case BS:    /* Backspace -- move 1 left */
  108.             /* Rely on vtsetcursor's clipping */
  109.             vtsetcursor(vt, vt->cur_row, vt->cur_col - 1);
  110.             /* Don't erase --
  111.                that's part of intelligent echoing */
  112.             break;
  113.         
  114.         case TAB:    /* Tab -- move to next tab stop */
  115.             /* Rely on vtsetcursor's clipping */
  116.             /* TO DO: use programmable tab stops! */
  117.             vtsetcursor(vt, vt->cur_row,
  118.                 (vt->cur_col & ~7) + 8);
  119.             /* Normalize cursor (may cause scroll!) */
  120.             vtputstring(vt, "", 0);
  121.             break;
  122.         
  123.         case LF:    /* Linefeed -- move down one line */
  124.             if (vt->nlcr)    /* First a \r? */
  125.                 vtsetcursor(vt, vt->cur_row, 0);
  126.             vtlinefeed(vt, 1);
  127.             break;
  128.         
  129.         case FF:    /* Formfeed */
  130.             /* vtreset(vt); */
  131.             break;
  132.         
  133.         case CR:    /* Return -- to col 0 on same line */
  134.             vtsetcursor(vt, vt->cur_row, 0);
  135.             break;
  136.         
  137.         case ' ':    /* In case isprint(c) fails for space */
  138.             vtputstring(vt, " ", 1);
  139.             break;
  140.  
  141.         default:
  142.             D( printf("Unrecognized unprintable character 0x%x\n",
  143.                                 text[-1]) );
  144.             FAIL();
  145.             break;
  146.         }
  147.     }
  148.  
  149.     /* We fall through the previous loop when we get a printable
  150.        character */
  151.     
  152.     {
  153.         char *p = text;
  154.         
  155.         while (PRINTABLE(*++p)) {
  156.             /* At least one character guaranteed! */
  157.             if (p >= end)
  158.                 break;
  159.         }
  160.         vtputstring(vt, text, (int)(p-text));
  161.         text = p;
  162.         goto again;
  163.     }
  164. }
  165.  
  166. /* Action function called after ESC seen */
  167.  
  168. STATIC char *
  169. esc_action(vt, text, end)
  170.     VT *vt;
  171.     char *text, *end;
  172. {
  173.     if (text >= end) {
  174.         vt->action = esc_action;
  175.         return NULL;
  176.     }
  177.     switch (*text++) {
  178. /*
  179.     case '(':
  180.     case ')':
  181.     case '*':
  182.     case '+':
  183.         return cset_action(vt, text, end);
  184. */
  185.     case '=':
  186.         vt->keypadmode = TRUE;
  187.         break;
  188.     case '>':
  189.         vt->keypadmode = FALSE;
  190.         break;
  191.     case '7':
  192.         vtsavecursor(vt);
  193.         break;
  194.     case '8':
  195.         vtrestorecursor(vt);
  196.         break;
  197.     case 'D':
  198.         vtlinefeed(vt, 1);
  199.         break;
  200.     case 'E':
  201.         /* Next Line */
  202.         break;
  203.     case 'H':
  204.         /* Tab set */
  205.         break;
  206.     case 'M':
  207.         vtrevlinefeed(vt, 1);
  208.         break;
  209.     case '[':
  210.         vt->nextarg = vt->args;
  211.         *vt->nextarg = -1;
  212.         vt->modarg = '\0';
  213.         return ansi_params(vt, text, end);
  214.     case 'c':
  215.         vtreset(vt);
  216.         break;
  217.     default:
  218.         D( printf("Urecognized: esc-%c (0x%x)\n",
  219.                 text[-1], text[-1]) );
  220.         FAIL();
  221.         break;
  222.     }
  223.     return text;
  224. }
  225.  
  226. /* Action function called after ESC-[ plus possible parameters seen */
  227.  
  228. STATIC char *
  229. ansi_params(vt, text, end)
  230.     VT *vt;
  231.     char *text, *end;
  232. {
  233. again:
  234.     if (text >= end) {
  235.         vt->action = ansi_params;
  236.         return NULL;
  237.     }
  238.     if (isdigit(*text)) {
  239.         long a = *vt->nextarg;
  240.         if (a < 0) /* Still unused? */
  241.             a = 0;
  242.         do {
  243.             a = a*10 + (*text - '0');
  244.             CLIPMAX(a, 0x7fff); /* Avoid overflow */
  245.         } while (++text < end && isdigit(*text));
  246.         *vt->nextarg = a; /* Remember arg under construction */
  247.         if (text >= end)
  248.             goto again;
  249.     }
  250.     switch (*text) {
  251.  
  252.     case ';': /* Arg no longer under construction */
  253.         ++text;
  254.         if (vt->nextarg < &vt->args[VTNARGS-1])
  255.             ++vt->nextarg; /* Else: overflow; who cares? */
  256.         *vt->nextarg = -1; /* Mark unused */
  257.         goto again;
  258.  
  259.     case '?':
  260.         ++text;
  261.         if (vt->nextarg == vt->args && /* No arguments yet */
  262.             *vt->nextarg < 0 && vt->modarg == '\0') {
  263.             vt->modarg = '?';
  264.             goto again;
  265.         }
  266.         else { /* Illegal here */
  267.             D( printf("Wrong argcount in DEC private mode\n") );
  268.             FAIL();
  269.             return text;
  270.         }
  271.  
  272.     default:
  273.         return ansi_execute(vt, text);
  274.     }
  275. }
  276.  
  277. /* Called after complete ESC [ ? <number> h is parsed.
  278.    This is called DEC private mode set. Most stuff is not
  279.    implemented. The vt is guarantueed to contain the one
  280.    and only argument allowed here. */
  281.  
  282. STATIC void
  283. vtprivset(vt)
  284.     VT *vt;
  285. {
  286.     switch (vt->args[0]) {
  287.     case 1:    /* Application cursor keys */
  288.         if (!vt->keypadmode) {
  289.             vt->keypadmode = 1;
  290.             vt->flagschanged = 1;
  291.         }
  292.         break;
  293. #if 0
  294.     case 3: /* 132 column mode */
  295.     case 4: /* Smooth (slow) scroll */
  296. #endif
  297.     case 5: /* Reverse video */
  298.         wfleep();
  299.         break;
  300. #if 0
  301.     case 6: /* Origin mode */
  302.     case 7: /* Wraparound mode */
  303.     case 8: /* Autorepeat keys */
  304. #endif
  305.     case 9: /* Send MIT mouse row & column on Button Press */
  306.         if (!vt->mitmouse) { /* If not already so */
  307.             vt->mitmouse = 1;
  308.             vt->flagschanged = 1;
  309.         }
  310.         break;
  311. #if 0
  312.     case 38: /* Enter Tektronix Mode */
  313.     case 40: /* Allow 80 <-> 132 mode */
  314.     case 41: /* Curses(5) fix */
  315.     case 44: /* Turn on margin bell */
  316.     case 45: /* Reverse wraparound mode */
  317.     case 46: /* Start logging */
  318.     case 47: /* Use alternate screen buffer */
  319.     case 1000: /* Send vt200 mouse row & column on Button Press */
  320.     case 1003: /* Send vt200 Hilite mouse row & column on Button Press */
  321. #endif
  322.     default:
  323.         D( printf("Unsupported DEC private mode set:") );
  324.         D( printf("esc [ ? %d h\n", vt->args[0]) );
  325.         wfleep();
  326.     }
  327. }
  328.  
  329. /* Called after complete ESC [ ? <number> l is parsed.
  330.    This is called DEC private mode reset. The vt is guarantueed
  331.    to contain the one and only argument allowed here. */
  332.  
  333. STATIC void
  334. vtprivreset(vt)
  335.     VT *vt;
  336. {
  337.     switch (vt->args[0]) {
  338.     case 1: /* Normal cursor keys */
  339.         if (vt->keypadmode) {
  340.             vt->keypadmode = 0;
  341.             vt->flagschanged = 1;
  342.         }
  343.         break;
  344. #if 0    /* These are not supprted: */
  345.     case 3: /* 80 column mode */
  346.     case 4: /* Jumpscroll */
  347. #endif
  348.     case 5: /* Normal video (i.e. not reverse) */
  349.         /* XXX Why this beep? */
  350.         wfleep();
  351.         break;
  352. #if 0
  353.     case 6: /* Normal cursor mode */
  354.     case 7: /* No wraparound */
  355.     case 8: /* No autorepeat */
  356.         break;
  357. #endif
  358.     case 9: /* Don't send mouse row & column on button press */
  359.     case 1000:    /* Same */
  360.     case 1003:    /* Same */
  361.         if (vt->mitmouse) { /* If not already so */
  362.             vt->mitmouse = 0;
  363.             vt->flagschanged = 1;
  364.         }
  365.         break;
  366. #if 0
  367.     case 40: /* Disallow 80 <-> 132 mode */
  368.     case 41: /* No curses(5) fix */
  369.     case 44: /* Turn off Margin bell */
  370.     case 45: /* No reverse wraparound */
  371.     case 46: /* Stop logging */
  372.     case 47: /* Use normal screen buffer (opposed to alternate buffer) */
  373.         break;
  374. #endif
  375.     default:
  376.         D( printf("Unsupported DEC private mode reset:") );
  377.         D( printf("esc [ ? %d l\n", vt->args[0]) );
  378.         wfleep();
  379.         break;
  380.     }
  381. }
  382.  
  383. /* Action function called at last char of ANSI sequence.
  384.    (This is only called when the char is actually seen,
  385.    so there is no need for an 'end' parameter). */
  386.  
  387. STATIC char *
  388. ansi_execute(vt, text)
  389.     VT *vt;
  390.     char *text;
  391. {
  392.     int a1 = vt->args[0];
  393.     int a2 = (vt->nextarg > vt->args) ? vt->args[1] : -1;
  394.  
  395.     if (vt->modarg == '?') {
  396.         /* These escape sequences have exactly one numeric parameter */
  397.         if (a1 < 0 || a2 > 0) {
  398.             wfleep();
  399.             return text+1;
  400.         }
  401.         switch (*text++) {
  402.         case 'h':    /* DEC Private mode Set */
  403.             vtprivset(vt);
  404.             break;
  405.         case 'l':    /* DEC Private mode Reset */
  406.             vtprivreset(vt);
  407.             break;
  408.         /* To do: add private mode memory to vt-descriptor? */
  409.         case 'r':    /* DEC Private mode Restore */
  410.         case 's':    /* DEC Private mode Save */
  411.         default:
  412.             /* Not supported or simply wrong */
  413.             wfleep();
  414.         }
  415.         return text;
  416.     }
  417.  
  418.     CLIPMIN(a1, 1);
  419.     CLIPMIN(a2, 1);
  420.  
  421.     switch (*text++) {
  422.     case '@': vtinschars(vt, a1);        break;
  423.     case 'A': vtarrow(vt, WC_UP, a1);    break;
  424.     case 'B': vtarrow(vt, WC_DOWN, a1);    break;
  425.     case 'C': vtarrow(vt, WC_RIGHT, a1);    break;
  426.     case 'D': vtarrow(vt, WC_LEFT, a1);    break;
  427.     case 'H':
  428.     case 'f': if (vt->nextarg > &vt->args[0])
  429.             vtsetcursor(vt, vt->topterm + a1 - 1, a2 - 1);
  430.           else vtsetcursor(vt, vt->topterm, 0);
  431.           break;
  432.     case 'J':
  433.         switch (vt->args[0]) {
  434.         case -1:
  435.         case 0:
  436.             vteosclear(vt, vt->topterm, 0);
  437.             break;
  438.         case 1:
  439.             /* clear above cursor */
  440.             break;
  441.         case 2:
  442.             vteosclear(vt, vt->cur_row, vt->cur_col);
  443.             break;
  444.         default:
  445.             FAIL();
  446.             break;
  447.         }
  448.         break;
  449.     case 'K':
  450.         switch (vt->args[0]) {
  451.         case -1:
  452.         case 0:
  453.             vteolclear(vt, vt->cur_row, vt->cur_col);
  454.             break;
  455.         case 1:
  456.             /* Clear left of cursor */
  457.             break;
  458.         case 2:
  459.             vteolclear(vt, vt->cur_row, 0);
  460.             break;
  461.         default:
  462.             FAIL();
  463.             break;
  464.         }
  465.         break;
  466.     case 'L': vtinslines(vt, a1);        break;
  467.     case 'M': vtdellines(vt, a1);        break;
  468.     case 'P': vtdelchars(vt, a1);        break;
  469.     case 'S': vtlinefeed(vt, a1);        break;
  470.     case 'T': vtrevlinefeed(vt, a1);    break;
  471.     case 'c': vtsendid(vt); break;
  472.     case 'g': /* Tab clear */        break;
  473.         /* 0: current col; 3: all */
  474.     case 'h': vtsetoptions(vt, TRUE);    break;
  475.     case 'l': vtsetoptions(vt, FALSE);    break;
  476.     case 'm': vtsetattrlist(vt);        break;
  477.     case 'n':
  478.         if (a1 == 6) vtsendpos(vt);
  479.         /* 5: echo 'ESC [ 0 n' */
  480.         break;
  481.     case 'r':
  482.         vtsetscroll(vt, vt->topterm+vt->args[0]-1, vt->topterm+a2);
  483.         break;
  484.     case 'x': /* Send terminal params */
  485.         break;
  486.     default:
  487.         FAIL();
  488.         break;
  489.     }
  490.  
  491.     return text;
  492. }
  493.  
  494. /* Set/reset numbered options given in args array */
  495.  
  496. STATIC void
  497. vtsetoptions(vt, flag)
  498.     VT *vt;
  499.     bool flag; /* Set/reset */
  500. {
  501.     short *a;
  502.     for (a = vt->args; a <= vt->nextarg; ++a) {
  503.         switch (*a) {
  504.         case 4:
  505.             vtsetinsert(vt, flag);
  506.             break;
  507.         case -1:
  508.             /* Empty parameter, don't beep */
  509.             break;
  510.         default:
  511.             FAIL();
  512.             break;
  513.         }
  514.     }
  515. }
  516.  
  517. /* Set/reset output mode attributes given in args array */
  518.  
  519. STATIC void
  520. vtsetattrlist(vt)
  521.     VT *vt;
  522. {
  523.     short *a;
  524.     for (a = vt->args; a <= vt->nextarg; ++a) {
  525.         switch (*a) {
  526.         case -1:
  527.             if (a == vt->args)
  528.                 vtresetattr(vt);
  529.             break;
  530.         case 0:
  531.             vtresetattr(vt);
  532.             break;
  533.         default:
  534.             vtsetattr(vt, *a);
  535.             break;
  536.         }
  537.     }
  538. }
  539.